HW 3 - Presentation
install.packages("choroplethrMaps")
Installing package into 㤼㸱C:/Users/quynh/OneDrive/Documents/R/win-library/4.0㤼㸲
(as 㤼㸱lib㤼㸲 is unspecified)
trying URL 'https://cran.rstudio.com/bin/windows/contrib/4.0/choroplethrMaps_1.0.1.zip'
Content type 'application/zip' length 2178888 bytes (2.1 MB)
downloaded 2.1 MB
package ‘choroplethrMaps’ successfully unpacked and MD5 sums checked
The downloaded binary packages are in
C:\Users\quynh\AppData\Local\Temp\RtmpoxNrqd\downloaded_packages
library(shiny)
library(ggplot2)
library(plotly)
library(tidyr)
library(dplyr)
library(countrycode)
library(choroplethr)
gdp_per_cap <-
read.csv(
"./data/income_per_person_gdppercapita_ppp_inflation_adjusted.csv",
header = TRUE,
stringsAsFactors = FALSE,
check.names = FALSE
)
pop <-
read.csv(
"./data/population_total.csv",
header = TRUE,
stringsAsFactors = FALSE,
check.names = FALSE
)
coal_df <-
read.csv(
"./data/coal_consumption_total.csv",
header = TRUE,
stringsAsFactors = FALSE,
check.names = FALSE
)
yearly_co2 <-
read.csv(
"./data/yearly_co2_emissions_1000_tonnes.csv",
header = TRUE,
stringsAsFactors = FALSE,
check.names = FALSE
)
wood_removal <-
read.csv(
"./data/wood_removal_cubic_meters.csv",
header = TRUE,
stringsAsFactors = FALSE,
check.names = FALSE
)
total_sulfur <-
read.csv(
"./data/total_sulfur_emission_kilotonnes.csv",
header = TRUE,
stringsAsFactors = FALSE,
check.names = FALSE
)
land_temp <-
read.csv(
"./data/GlobalLandTemperaturesByCountry.csv",
header = TRUE,
stringsAsFactors = FALSE,
check.names = FALSE
)
gdp_per_cap$continent <- countrycode(sourcevar = gdp_per_cap[, "country"],
origin = "country.name",
destination = "continent")
pop$continent <- countrycode(sourcevar = pop[, "country"],
origin = "country.name",
destination = "continent")
coal_df$continent <- countrycode(sourcevar = coal_df[, "country"],
origin = "country.name",
destination = "continent")
yearly_co
land_temp$continent <- countrycode(sourcevar = land_temp[, "country"],
origin = "country.name",
destination = "continent")
Some values were not matched unambiguously: Åland, Africa, Antarctica, Asia, Baker Island, Curaçao, Europe, French Southern And Antarctic Lands, Heard Island And Mcdonald Islands, Kingman Reef, North America, Oceania, Palmyra Atoll, Saint Barthélemy, Saint Martin, South America, South Georgia And The South Sandwich Isla, Virgin Islands
yearly_co2$continent <- countrycode(sourcevar = yearly_co2[, "country"],
origin = "country.name",
destination = "continent")
wood_removal$continent <- countrycode(sourcevar = wood_removal[, "country"],
origin = "country.name",
destination = "continent")
total_sulfur$continent <- countrycode(sourcevar = total_sulfur[, "country"],
origin = "country.name",
destination = "continent")
library(readr)
land_temp <- land_temp %>% drop_na("continent")
drop <- c("AverageTemperatureUncertainty")
land_temp <- land_temp[!(names(land_temp) %in% drop)]
land_temp <- within(land_temp,
date <- ifelse(!is.na(as.Date(land_temp$dt, "%Y-%m-%d")),
as.character(as.Date(land_temp$dt, "%Y-%m-%d")),
as.character(as.Date(land_temp$dt, "%m/%d/%Y"))))
land_temp <- land_temp[!(names(land_temp) %in% drop)]
land_temp <- na.omit(land_temp)
land_temp
library(lubridate)
land_df <- land_temp %>%
mutate(country, year = year(date)) %>%
group_by(country, year, continent)
drop <- c("dt")
land_df <- land_df[!(names(land_df) %in% drop)]
land_df <- aggregate(land_df$AverageTemperature,
by=list(year=land_df$year,
country=land_df$country,
continent=land_df$continent),
FUN=mean, na.action = na.omit)
land_df <- land_df %>%
mutate(AverageTemperature = x * 1.8 + 32)
drop <- c("x")
land_df <- land_df[!(names(land_df) %in% drop)]
names(land_df)[4] <- "AverageTemperature"
land_df
df_co2 <- yearly_co2%>%
pivot_longer(c('1850':'2012'), names_to = "year",
values_to = "co2_emissions") %>%
select(country, year, co2_emissions)
df_co2 <- na.omit(df_co2, cols=c("co2_emissions"))
df_gdp <- gdp_per_cap%>%
pivot_longer(c('1850':'2012'), names_to = "year", values_to = "gdpPercap") %>%
select(country, year, gdpPercap)
df_pop <- pop%>%
pivot_longer(c('1850':'2012'), names_to = "year", values_to = "pop") %>%
select(country, year, pop)
df_land <- filter(land_df, year >= 1850) %>% filter(year <= 2012)
df_land <- df_land %>% mutate(year = as.character(year))
first_graph <- left_join(df_pop, df_co2) %>%
merge(df_land)
Joining, by = c("country", "year")
first_graph <- na.omit(first_graph, cols=c("co2_emissions"))
first_graph$CODE <- countrycode(first_graph$country, origin = 'country.name', destination = 'genc3c')
first_graph
library(plotly)
df_example <- first_graph %>%
filter(year == 2000)
fig <- plot_ly(df_example, type='choropleth',
locations=df_example$CODE,
z=df_example$AverageTemperature,
text=df_example$country)
fig
#head(df_example)
library(shiny)
con <- factor(c('Asia','Africa', 'Americas', 'Europe', 'Oceania'))
print(levels(con))
[1] "Africa" "Americas" "Asia" "Europe" "Oceania"
ui <- fluidPage(
titlePanel("C02 vs Land Temperature"),
sidebarLayout(
sidebarPanel(
helpText("Interavtive plotting of data usng R shiny"),
sliderInput("year", "Year",
min = range(as.numeric( first_graph$year))[1],
max = range(as.numeric( first_graph$year))[2],
value = range(as.numeric( first_graph$year))[1],
sep = "",
step = 5,
animate = animationOptions(interval = 500)
)
),
mainPanel(plotOutput("gap"))
)
)
server <- function(input, output) {
output$gap <- renderPlot({
df <- first_graph %>%
filter(year == input$year) %>%
rename(region = country, value = AverageTemperature) %>%
mutate(region = tolower(region)) %>%
mutate(region = recode(region,
"united states" = "united states of america",
"congo, dem. rep." = "democratic republic of the congo",
"congo, rep." = "republic of congo",
"korea, dem. rep." = "south korea",
"korea. rep." = "north korea",
"tanzania" = "united republic of tanzania",
"serbia" = "republic of serbia",
"slovak republic" = "slovakia",
"yemen, rep." = "yemen"))
country_choropleth(df) + scale_fill_brewer(palette="YlOrRd")
})
}
shinyApp(ui = ui, server = server)
Listening on http://127.0.0.1:7181
NA
library(shiny)
con <- factor(c('Asia','Africa', 'Americas', 'Europe', 'Oceania'))
print(levels(con))
[1] "Africa" "Americas" "Asia" "Europe" "Oceania"
ui <- fluidPage(
titlePanel("C02 vs Land Temperature"),
sidebarLayout(
sidebarPanel(
helpText("Interavtive plotting of data usng R shiny"),
checkboxGroupInput("continent",
"Choose a continent",
choices = levels(con),
selected = levels(con)),
sliderInput("quantiles", "CO2 Quantiles of interest",
min = 0,
max = 100,
value = c(0, 100),
sep = ""),
sliderInput("year", "Year",
min = range(as.numeric(first_graph$year))[1],
max = range(as.numeric(first_graph$year))[2],
value = range(as.numeric(first_graph$year))[1],
sep = "",
step = 5,
animate = animationOptions(interval = 500)
)
),
mainPanel(plotOutput("gap"))
)
)
max_x <- max(first_graph$co2_emissions)
min_x <- min(first_graph$co2_emissions)
max_y <- max(first_graph$AverageTemperature)
min_y <- min(first_graph$AverageTemperature)
print(min_x)
[1] 0
print(max_x)
[1] 9640000
print(min_y)
[1] -4.4833
print(max_y)
[1] 86.22875
server <- function(input, output) {
output$gap <- renderPlot({
df <- first_graph %>%
filter(year == input$year) %>%
filter(continent %in% input$continent)
filter(df, co2_emissions <= quantile(df$co2_emissions,
probs = (max(input$quantiles)/100),
na.rm = TRUE)) %>%
filter(co2_emissions >= quantile(df$co2_emissions,
probs = (min(input$quantiles)/100),
na.rm = TRUE)) %>%
ggplot(aes(x = co2_emissions,
y = AverageTemperature, color=continent)) +
geom_point(aes(size = pop, frame = year, ids = country)) +
scale_x_log10(limits = c(min_x + 0.1, max_x)) +
ylim(min_y, max_y) +
theme(legend.title = element_blank())
})
}
shinyApp(ui = ui, server = server)
Listening on http://127.0.0.1:7181
NA
start_year <- 1965
end_year <- 2019
df <- reshape(gdp_per_cap,
direction="long",
varying = list(names(gdp_per_cap)
[(start_year - 1800 + 2): (end_year - 1800 + 2)]),
v.names = "gdpPercap",
idvar = c("country"),
timevar = "year",
times = start_year:end_year)
df_2 <- reshape(coal_df,
direction="long",
varying = list(names(coal_df)
[2: (end_year - start_year + 2)]),
v.names = "coal",
idvar = c("country"),
timevar = "year",
times = start_year:end_year)
df_3 <- reshape(pop,
direction="long",
varying = list(names(pop)
[(start_year - 1800 + 2): (end_year - 1800 + 2)]),
v.names = "pop",
idvar = c("country"),
timevar = "year",
times = start_year:end_year)
keeps_pop <- c("country", "continent", "year", "pop")
keeps_coal <- c("country", "continent", "year", "coal")
keeps_gdp <- c("country", "continent", "year", "gdpPercap")
df_3 <- df_3[keeps_pop]
df_2 <- df_2[keeps_coal]
df <- df[keeps_gdp]
merge_df <- merge(df, df_3) %>% merge(df_2)
head(merge_df)
# Remove any unnecessary data
remove(df)
remove(df_2)
remove(df_3)
gg <- ggplot(merge_df, aes(coal, gdpPercap, color = continent)) +
geom_point(aes(size = pop, frame = year, ids = country)) +
scale_x_log10() +
scale_y_log10() +
theme(legend.title = element_blank())
Ignoring unknown aesthetics: frame, ids
ggplotly(gg)
Transformation introduced infinite values in continuous x-axis
Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Ctrl+Alt+I.
When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Ctrl+Shift+K to preview the HTML file).
The preview shows you a rendered HTML copy of the contents of the editor. Consequently, unlike Knit, Preview does not run any R code chunks. Instead, the output of the chunk when it was last run in the editor is displayed.
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojICoqSFcgMyAtIFByZXNlbnRhdGlvbioqDQoNCmBgYHtyfQ0KaW5zdGFsbC5wYWNrYWdlcygiY2hvcm9wbGV0aHJNYXBzIikNCmxpYnJhcnkoc2hpbnkpDQpsaWJyYXJ5KGdncGxvdDIpIA0KbGlicmFyeShwbG90bHkpDQpsaWJyYXJ5KHRpZHlyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoY291bnRyeWNvZGUpDQpsaWJyYXJ5KGNob3JvcGxldGhyKQ0KYGBgDQoNCmBgYHtyfQ0KZ2RwX3Blcl9jYXAgPC0gDQogIHJlYWQuY3N2KA0KICAgICIuL2RhdGEvaW5jb21lX3Blcl9wZXJzb25fZ2RwcGVyY2FwaXRhX3BwcF9pbmZsYXRpb25fYWRqdXN0ZWQuY3N2IiwgDQogICAgaGVhZGVyID0gVFJVRSwgDQogICAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFLA0KICAgIGNoZWNrLm5hbWVzID0gRkFMU0UNCiAgICApDQpwb3AgPC0NCiAgcmVhZC5jc3YoDQogICAgIi4vZGF0YS9wb3B1bGF0aW9uX3RvdGFsLmNzdiIsDQogICAgaGVhZGVyID0gVFJVRSwNCiAgICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UsDQogICAgY2hlY2submFtZXMgPSBGQUxTRQ0KICApDQpjb2FsX2RmIDwtDQogIHJlYWQuY3N2KA0KICAgICIuL2RhdGEvY29hbF9jb25zdW1wdGlvbl90b3RhbC5jc3YiLA0KICAgIGhlYWRlciA9IFRSVUUsDQogICAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFLA0KICAgIGNoZWNrLm5hbWVzID0gRkFMU0UNCiAgKQ0KDQp5ZWFybHlfY28yIDwtDQogIHJlYWQuY3N2KA0KICAgICIuL2RhdGEveWVhcmx5X2NvMl9lbWlzc2lvbnNfMTAwMF90b25uZXMuY3N2IiwNCiAgICBoZWFkZXIgPSBUUlVFLA0KICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSwNCiAgICBjaGVjay5uYW1lcyA9IEZBTFNFDQogICkNCndvb2RfcmVtb3ZhbCA8LQ0KICByZWFkLmNzdigNCiAgICAiLi9kYXRhL3dvb2RfcmVtb3ZhbF9jdWJpY19tZXRlcnMuY3N2IiwNCiAgICBoZWFkZXIgPSBUUlVFLA0KICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSwNCiAgICBjaGVjay5uYW1lcyA9IEZBTFNFDQogICkNCnRvdGFsX3N1bGZ1ciA8LQ0KICByZWFkLmNzdigNCiAgICAiLi9kYXRhL3RvdGFsX3N1bGZ1cl9lbWlzc2lvbl9raWxvdG9ubmVzLmNzdiIsDQogICAgaGVhZGVyID0gVFJVRSwNCiAgICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UsDQogICAgY2hlY2submFtZXMgPSBGQUxTRQ0KICApDQpsYW5kX3RlbXAgPC0NCiAgcmVhZC5jc3YoDQogICAgIi4vZGF0YS9HbG9iYWxMYW5kVGVtcGVyYXR1cmVzQnlDb3VudHJ5LmNzdiIsDQogICAgaGVhZGVyID0gVFJVRSwNCiAgICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UsDQogICAgY2hlY2submFtZXMgPSBGQUxTRQ0KICApDQpgYGANCg0KYGBge3J9DQpnZHBfcGVyX2NhcCRjb250aW5lbnQgPC0gY291bnRyeWNvZGUoc291cmNldmFyID0gZ2RwX3Blcl9jYXBbLCAiY291bnRyeSJdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yaWdpbiA9ICJjb3VudHJ5Lm5hbWUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc3RpbmF0aW9uID0gImNvbnRpbmVudCIpDQpwb3AkY29udGluZW50IDwtIGNvdW50cnljb2RlKHNvdXJjZXZhciA9IHBvcFssICJjb3VudHJ5Il0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JpZ2luID0gImNvdW50cnkubmFtZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVzdGluYXRpb24gPSAiY29udGluZW50IikNCmNvYWxfZGYkY29udGluZW50IDwtIGNvdW50cnljb2RlKHNvdXJjZXZhciA9IGNvYWxfZGZbLCAiY291bnRyeSJdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yaWdpbiA9ICJjb3VudHJ5Lm5hbWUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc3RpbmF0aW9uID0gImNvbnRpbmVudCIpDQpgYGANCg0KeWVhcmx5X2NvDQoNCmBgYHtyfQ0KbGFuZF90ZW1wJGNvbnRpbmVudCA8LSBjb3VudHJ5Y29kZShzb3VyY2V2YXIgPSBsYW5kX3RlbXBbLCAiY291bnRyeSJdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yaWdpbiA9ICJjb3VudHJ5Lm5hbWUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc3RpbmF0aW9uID0gImNvbnRpbmVudCIpDQp5ZWFybHlfY28yJGNvbnRpbmVudCA8LSBjb3VudHJ5Y29kZShzb3VyY2V2YXIgPSB5ZWFybHlfY28yWywgImNvdW50cnkiXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmlnaW4gPSAiY291bnRyeS5uYW1lIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZXN0aW5hdGlvbiA9ICJjb250aW5lbnQiKQ0Kd29vZF9yZW1vdmFsJGNvbnRpbmVudCA8LSBjb3VudHJ5Y29kZShzb3VyY2V2YXIgPSB3b29kX3JlbW92YWxbLCAiY291bnRyeSJdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yaWdpbiA9ICJjb3VudHJ5Lm5hbWUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc3RpbmF0aW9uID0gImNvbnRpbmVudCIpDQp0b3RhbF9zdWxmdXIkY29udGluZW50IDwtIGNvdW50cnljb2RlKHNvdXJjZXZhciA9IHRvdGFsX3N1bGZ1clssICJjb3VudHJ5Il0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgb3JpZ2luID0gImNvdW50cnkubmFtZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVzdGluYXRpb24gPSAiY29udGluZW50IikNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkocmVhZHIpDQpsYW5kX3RlbXAgPC0gbGFuZF90ZW1wICU+JSBkcm9wX25hKCJjb250aW5lbnQiKQ0KZHJvcCA8LSBjKCJBdmVyYWdlVGVtcGVyYXR1cmVVbmNlcnRhaW50eSIpDQpsYW5kX3RlbXAgPC0gbGFuZF90ZW1wWyEobmFtZXMobGFuZF90ZW1wKSAlaW4lIGRyb3ApXQ0KbGFuZF90ZW1wIDwtIHdpdGhpbihsYW5kX3RlbXAsDQogICAgICAgICAgICAgICAgICAgIGRhdGUgPC0gaWZlbHNlKCFpcy5uYShhcy5EYXRlKGxhbmRfdGVtcCRkdCwgIiVZLSVtLSVkIikpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLmNoYXJhY3Rlcihhcy5EYXRlKGxhbmRfdGVtcCRkdCwgIiVZLSVtLSVkIikpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLmNoYXJhY3Rlcihhcy5EYXRlKGxhbmRfdGVtcCRkdCwgIiVtLyVkLyVZIikpKSkgDQpsYW5kX3RlbXAgPC0gbGFuZF90ZW1wWyEobmFtZXMobGFuZF90ZW1wKSAlaW4lIGRyb3ApXQ0KbGFuZF90ZW1wIDwtIG5hLm9taXQobGFuZF90ZW1wKQ0KbGFuZF90ZW1wDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxhbmRfZGYgPC0gbGFuZF90ZW1wICU+JQ0KICBtdXRhdGUoY291bnRyeSwgeWVhciA9IHllYXIoZGF0ZSkpICU+JQ0KICBncm91cF9ieShjb3VudHJ5LCB5ZWFyLCBjb250aW5lbnQpDQpkcm9wIDwtIGMoImR0IikNCmxhbmRfZGYgPC0gbGFuZF9kZlshKG5hbWVzKGxhbmRfZGYpICVpbiUgZHJvcCldDQpsYW5kX2RmIDwtIGFnZ3JlZ2F0ZShsYW5kX2RmJEF2ZXJhZ2VUZW1wZXJhdHVyZSwgDQogICAgICAgICAgICAgICAgICAgICBieT1saXN0KHllYXI9bGFuZF9kZiR5ZWFyLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY291bnRyeT1sYW5kX2RmJGNvdW50cnksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRpbmVudD1sYW5kX2RmJGNvbnRpbmVudCksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRlVOPW1lYW4sIG5hLmFjdGlvbiA9IG5hLm9taXQpDQpsYW5kX2RmIDwtIGxhbmRfZGYgJT4lDQogIG11dGF0ZShBdmVyYWdlVGVtcGVyYXR1cmUgPSB4ICogMS44ICsgMzIpDQpkcm9wIDwtIGMoIngiKQ0KbGFuZF9kZiA8LSBsYW5kX2RmWyEobmFtZXMobGFuZF9kZikgJWluJSBkcm9wKV0NCm5hbWVzKGxhbmRfZGYpWzRdIDwtICJBdmVyYWdlVGVtcGVyYXR1cmUiDQpsYW5kX2RmICANCmBgYA0KDQpgYGB7cn0NCmRmX2NvMiA8LSB5ZWFybHlfY28yJT4lDQogIHBpdm90X2xvbmdlcihjKCcxODUwJzonMjAxMicpLCBuYW1lc190byA9ICJ5ZWFyIiwgDQogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAiY28yX2VtaXNzaW9ucyIpICU+JQ0KICBzZWxlY3QoY291bnRyeSwgeWVhciwgY28yX2VtaXNzaW9ucykNCmRmX2NvMiA8LSBuYS5vbWl0KGRmX2NvMiwgY29scz1jKCJjbzJfZW1pc3Npb25zIikpDQpkZl9nZHAgPC0gZ2RwX3Blcl9jYXAlPiUNCiAgcGl2b3RfbG9uZ2VyKGMoJzE4NTAnOicyMDEyJyksIG5hbWVzX3RvID0gInllYXIiLCB2YWx1ZXNfdG8gPSAiZ2RwUGVyY2FwIikgJT4lDQogIHNlbGVjdChjb3VudHJ5LCB5ZWFyLCBnZHBQZXJjYXApDQpkZl9wb3AgPC0gcG9wJT4lDQogIHBpdm90X2xvbmdlcihjKCcxODUwJzonMjAxMicpLCBuYW1lc190byA9ICJ5ZWFyIiwgdmFsdWVzX3RvID0gInBvcCIpICU+JQ0KICBzZWxlY3QoY291bnRyeSwgeWVhciwgcG9wKQ0KZGZfbGFuZCA8LSBmaWx0ZXIobGFuZF9kZiwgeWVhciA+PSAxODUwKSAlPiUgZmlsdGVyKHllYXIgPD0gMjAxMikNCmRmX2xhbmQgPC0gZGZfbGFuZCAlPiUgbXV0YXRlKHllYXIgPSBhcy5jaGFyYWN0ZXIoeWVhcikpDQpgYGANCg0KYGBge3J9DQpmaXJzdF9ncmFwaCA8LSBsZWZ0X2pvaW4oZGZfcG9wLCBkZl9jbzIpICU+JQ0KICAgICAgICAgICAgICAgbWVyZ2UoZGZfbGFuZCkNCmZpcnN0X2dyYXBoIDwtIG5hLm9taXQoZmlyc3RfZ3JhcGgsIGNvbHM9YygiY28yX2VtaXNzaW9ucyIpKQ0KZmlyc3RfZ3JhcGgkQ09ERSA8LSBjb3VudHJ5Y29kZShmaXJzdF9ncmFwaCRjb3VudHJ5LCBvcmlnaW4gPSAnY291bnRyeS5uYW1lJywgZGVzdGluYXRpb24gPSAnZ2VuYzNjJykNCmZpcnN0X2dyYXBoDQpgYGANCg0KYGBge3J9DQoNCmRmX2V4YW1wbGUgPC0gZmlyc3RfZ3JhcGggJT4lDQogIGZpbHRlcih5ZWFyID09IDIwMDApDQpmaWcgPC0gcGxvdF9seShkZl9leGFtcGxlLCB0eXBlPSdjaG9yb3BsZXRoJywgDQogICAgICAgICAgICAgICBsb2NhdGlvbnM9ZGZfZXhhbXBsZSRDT0RFLCANCiAgICAgICAgICAgICAgIHo9ZGZfZXhhbXBsZSRBdmVyYWdlVGVtcGVyYXR1cmUsIA0KICAgICAgICAgICAgICAgdGV4dD1kZl9leGFtcGxlJGNvdW50cnkpDQpmaWcNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoc2hpbnkpDQpjb24gPC0gZmFjdG9yKGMoJ0FzaWEnLCdBZnJpY2EnLCAnQW1lcmljYXMnLCAnRXVyb3BlJywgJ09jZWFuaWEnKSkNCnByaW50KGxldmVscyhjb24pKQ0KdWkgPC0gZmx1aWRQYWdlKA0KICAgIHRpdGxlUGFuZWwoIkMwMiB2cyBMYW5kIFRlbXBlcmF0dXJlIiksDQogICAgDQogICAgc2lkZWJhckxheW91dCgNCiAgICAgICAgc2lkZWJhclBhbmVsKA0KICAgICAgICAgICAgaGVscFRleHQoIkludGVyYXZ0aXZlIHBsb3R0aW5nIG9mIGRhdGEgdXNuZyBSIHNoaW55IiksDQogICAgICAgICAgICANCiAgICAgICAgICAgIHNsaWRlcklucHV0KCJ5ZWFyIiwgIlllYXIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgbWluID0gcmFuZ2UoYXMubnVtZXJpYyggZmlyc3RfZ3JhcGgkeWVhcikpWzFdLA0KICAgICAgICAgICAgICAgICAgICAgICAgbWF4ID0gcmFuZ2UoYXMubnVtZXJpYyggZmlyc3RfZ3JhcGgkeWVhcikpWzJdLA0KICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSByYW5nZShhcy5udW1lcmljKCBmaXJzdF9ncmFwaCR5ZWFyKSlbMV0sDQogICAgICAgICAgICAgICAgICAgICAgICBzZXAgPSAiIiwNCiAgICAgICAgICAgICAgICAgICAgICAgIHN0ZXAgPSA1LA0KICAgICAgICAgICAgICAgICAgICAgICAgYW5pbWF0ZSA9IGFuaW1hdGlvbk9wdGlvbnMoaW50ZXJ2YWwgPSA1MDApDQogICAgICAgICAgICApDQogICAgICAgICksDQogICAgICAgIA0KICAgICAgICBtYWluUGFuZWwocGxvdE91dHB1dCgiZ2FwIikpDQogICAgKQ0KKQ0KDQoNCnNlcnZlciA8LSBmdW5jdGlvbihpbnB1dCwgb3V0cHV0KSB7DQogICAgDQogICAgb3V0cHV0JGdhcCA8LSByZW5kZXJQbG90KHsgDQogICAgICAgIGRmIDwtIGZpcnN0X2dyYXBoICU+JQ0KICAgICAgICAgICAgZmlsdGVyKHllYXIgPT0gaW5wdXQkeWVhcikgJT4lDQogICAgICAgICAgICByZW5hbWUocmVnaW9uID0gY291bnRyeSwgdmFsdWUgPSBBdmVyYWdlVGVtcGVyYXR1cmUpICU+JQ0KICAgIG11dGF0ZShyZWdpb24gPSB0b2xvd2VyKHJlZ2lvbikpICU+JQ0KICAgIG11dGF0ZShyZWdpb24gPSByZWNvZGUocmVnaW9uLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ1bml0ZWQgc3RhdGVzIiAgICA9ICJ1bml0ZWQgc3RhdGVzIG9mIGFtZXJpY2EiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAiY29uZ28sIGRlbS4gcmVwLiIgPSAiZGVtb2NyYXRpYyByZXB1YmxpYyBvZiB0aGUgY29uZ28iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb25nbywgcmVwLiIgICAgICA9ICJyZXB1YmxpYyBvZiBjb25nbyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgImtvcmVhLCBkZW0uIHJlcC4iID0gInNvdXRoIGtvcmVhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAia29yZWEuIHJlcC4iICAgICAgPSAibm9ydGgga29yZWEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ0YW56YW5pYSIgICAgICAgICA9ICJ1bml0ZWQgcmVwdWJsaWMgb2YgdGFuemFuaWEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICJzZXJiaWEiICAgICAgICAgICA9ICJyZXB1YmxpYyBvZiBzZXJiaWEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICJzbG92YWsgcmVwdWJsaWMiICA9ICJzbG92YWtpYSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgInllbWVuLCByZXAuIiAgICAgID0gInllbWVuIikpDQogICAgICAgIGNvdW50cnlfY2hvcm9wbGV0aChkZikgKyBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlPSJZbE9yUmQiKQ0KICAgICAgICANCiAgICB9KQ0KfQ0KDQpzaGlueUFwcCh1aSA9IHVpLCBzZXJ2ZXIgPSBzZXJ2ZXIpDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KHNoaW55KQ0KY29uIDwtIGZhY3RvcihjKCdBc2lhJywnQWZyaWNhJywgJ0FtZXJpY2FzJywgJ0V1cm9wZScsICdPY2VhbmlhJykpDQpwcmludChsZXZlbHMoY29uKSkNCnVpIDwtIGZsdWlkUGFnZSgNCiAgICB0aXRsZVBhbmVsKCJDMDIgdnMgTGFuZCBUZW1wZXJhdHVyZSIpLA0KICAgIA0KICAgIHNpZGViYXJMYXlvdXQoDQogICAgICAgIHNpZGViYXJQYW5lbCgNCiAgICAgICAgICAgIGhlbHBUZXh0KCJJbnRlcmF2dGl2ZSBwbG90dGluZyBvZiBkYXRhIHVzbmcgUiBzaGlueSIpLA0KICAgICAgICAgICAgDQogICAgICAgICAgICBjaGVja2JveEdyb3VwSW5wdXQoImNvbnRpbmVudCIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJDaG9vc2UgYSBjb250aW5lbnQiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaG9pY2VzID0gbGV2ZWxzKGNvbiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0ZWQgPSBsZXZlbHMoY29uKSksDQogICAgICAgICAgICANCiAgICAgICAgICAgIHNsaWRlcklucHV0KCJxdWFudGlsZXMiLCAiQ08yIFF1YW50aWxlcyBvZiBpbnRlcmVzdCIsDQogICAgICAgICAgICAgICAgICAgICAgICBtaW4gPSAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgbWF4ID0gMTAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSBjKDAsIDEwMCksDQogICAgICAgICAgICAgICAgICAgICAgICBzZXAgPSAiIiksDQogICAgICAgICAgICANCiAgICAgICAgICAgIHNsaWRlcklucHV0KCJ5ZWFyIiwgIlllYXIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgbWluID0gcmFuZ2UoYXMubnVtZXJpYyhmaXJzdF9ncmFwaCR5ZWFyKSlbMV0sDQogICAgICAgICAgICAgICAgICAgICAgICBtYXggPSByYW5nZShhcy5udW1lcmljKGZpcnN0X2dyYXBoJHllYXIpKVsyXSwNCiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlID0gcmFuZ2UoYXMubnVtZXJpYyhmaXJzdF9ncmFwaCR5ZWFyKSlbMV0sDQogICAgICAgICAgICAgICAgICAgICAgICBzZXAgPSAiIiwNCiAgICAgICAgICAgICAgICAgICAgICAgIHN0ZXAgPSA1LA0KICAgICAgICAgICAgICAgICAgICAgICAgYW5pbWF0ZSA9IGFuaW1hdGlvbk9wdGlvbnMoaW50ZXJ2YWwgPSA1MDApDQogICAgICAgICAgICApDQogICAgICAgICksDQogICAgICAgIA0KICAgICAgICBtYWluUGFuZWwocGxvdE91dHB1dCgiZ2FwIikpDQogICAgKQ0KKQ0KDQptYXhfeCA8LSBtYXgoZmlyc3RfZ3JhcGgkY28yX2VtaXNzaW9ucykNCm1pbl94IDwtIG1pbihmaXJzdF9ncmFwaCRjbzJfZW1pc3Npb25zKQ0KbWF4X3kgPC0gbWF4KGZpcnN0X2dyYXBoJEF2ZXJhZ2VUZW1wZXJhdHVyZSkNCm1pbl95IDwtIG1pbihmaXJzdF9ncmFwaCRBdmVyYWdlVGVtcGVyYXR1cmUpDQpwcmludChtaW5feCkNCnByaW50KG1heF94KQ0KcHJpbnQobWluX3kpDQpwcmludChtYXhfeSkNCg0Kc2VydmVyIDwtIGZ1bmN0aW9uKGlucHV0LCBvdXRwdXQpIHsNCiAgICANCiAgICBvdXRwdXQkZ2FwIDwtIHJlbmRlclBsb3QoeyANCiAgICAgICAgZGYgPC0gZmlyc3RfZ3JhcGggJT4lDQogICAgICAgICAgICBmaWx0ZXIoeWVhciA9PSBpbnB1dCR5ZWFyKSAlPiUNCiAgICAgICAgICAgIGZpbHRlcihjb250aW5lbnQgJWluJSBpbnB1dCRjb250aW5lbnQpDQogICAgICAgICAgICAgDQogICAgICAgICAgICBmaWx0ZXIoZGYsIGNvMl9lbWlzc2lvbnMgPD0gcXVhbnRpbGUoZGYkY28yX2VtaXNzaW9ucywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2JzID0gKG1heChpbnB1dCRxdWFudGlsZXMpLzEwMCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKSkgJT4lDQogICAgICAgICAgICBmaWx0ZXIoY28yX2VtaXNzaW9ucyA+PSBxdWFudGlsZShkZiRjbzJfZW1pc3Npb25zLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvYnMgPSAobWluKGlucHV0JHF1YW50aWxlcykvMTAwKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKSkgJT4lDQogICAgICAgICAgICBnZ3Bsb3QoYWVzKHggPSBjbzJfZW1pc3Npb25zLCANCiAgICAgICAgICAgICAgICAgICAgICAgeSA9IEF2ZXJhZ2VUZW1wZXJhdHVyZSwgY29sb3I9Y29udGluZW50KSkgKw0KICAgICAgICAgICAgZ2VvbV9wb2ludChhZXMoc2l6ZSA9IHBvcCwgZnJhbWUgPSB5ZWFyLCBpZHMgPSBjb3VudHJ5KSkgKyANCiAgICAgICAgICAgIHNjYWxlX3hfbG9nMTAobGltaXRzID0gYyhtaW5feCArIDAuMSwgbWF4X3gpKSArIA0KICAgICAgICAgICAgeWxpbShtaW5feSwgbWF4X3kpICsgDQogICAgICAgICAgICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpDQogICAgfSkNCn0NCg0Kc2hpbnlBcHAodWkgPSB1aSwgc2VydmVyID0gc2VydmVyKQ0KYGBgDQoNCmBgYHtyfQ0Kc3RhcnRfeWVhciA8LSAxOTY1DQplbmRfeWVhciA8LSAyMDE5DQpkZiA8LSByZXNoYXBlKGdkcF9wZXJfY2FwLA0KICAgICAgICAgICAgICBkaXJlY3Rpb249ImxvbmciLA0KICAgICAgICAgICAgICB2YXJ5aW5nID0gbGlzdChuYW1lcyhnZHBfcGVyX2NhcCkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgWyhzdGFydF95ZWFyIC0gMTgwMCArIDIpOiAoZW5kX3llYXIgLSAxODAwICsgMildKSwNCiAgICAgICAgICAgICAgdi5uYW1lcyA9ICJnZHBQZXJjYXAiLA0KICAgICAgICAgICAgICBpZHZhciA9IGMoImNvdW50cnkiKSwNCiAgICAgICAgICAgICAgdGltZXZhciA9ICJ5ZWFyIiwNCiAgICAgICAgICAgICAgdGltZXMgPSBzdGFydF95ZWFyOmVuZF95ZWFyKQ0KZGZfMiA8LSByZXNoYXBlKGNvYWxfZGYsDQogICAgICAgICAgICAgIGRpcmVjdGlvbj0ibG9uZyIsDQogICAgICAgICAgICAgIHZhcnlpbmcgPSBsaXN0KG5hbWVzKGNvYWxfZGYpDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIFsyOiAoZW5kX3llYXIgLSBzdGFydF95ZWFyICsgMildKSwNCiAgICAgICAgICAgICAgdi5uYW1lcyA9ICJjb2FsIiwNCiAgICAgICAgICAgICAgaWR2YXIgPSBjKCJjb3VudHJ5IiksDQogICAgICAgICAgICAgIHRpbWV2YXIgPSAieWVhciIsDQogICAgICAgICAgICB0aW1lcyA9IHN0YXJ0X3llYXI6ZW5kX3llYXIpDQpkZl8zIDwtIHJlc2hhcGUocG9wLA0KICAgICAgICAgICAgICBkaXJlY3Rpb249ImxvbmciLA0KICAgICAgICAgICAgICB2YXJ5aW5nID0gbGlzdChuYW1lcyhwb3ApDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIFsoc3RhcnRfeWVhciAtIDE4MDAgKyAyKTogKGVuZF95ZWFyIC0gMTgwMCArIDIpXSksDQogICAgICAgICAgICAgIHYubmFtZXMgPSAicG9wIiwNCiAgICAgICAgICAgICAgaWR2YXIgPSBjKCJjb3VudHJ5IiksDQogICAgICAgICAgICAgIHRpbWV2YXIgPSAieWVhciIsDQogICAgICAgICAgICAgIHRpbWVzID0gc3RhcnRfeWVhcjplbmRfeWVhcikNCmBgYA0KDQpgYGB7cn0NCmtlZXBzX3BvcCA8LSBjKCJjb3VudHJ5IiwgImNvbnRpbmVudCIsICJ5ZWFyIiwgInBvcCIpDQprZWVwc19jb2FsIDwtIGMoImNvdW50cnkiLCAiY29udGluZW50IiwgInllYXIiLCAiY29hbCIpDQprZWVwc19nZHAgPC0gYygiY291bnRyeSIsICJjb250aW5lbnQiLCAieWVhciIsICJnZHBQZXJjYXAiKQ0KZGZfMyA8LSBkZl8zW2tlZXBzX3BvcF0NCmRmXzIgPC0gZGZfMltrZWVwc19jb2FsXQ0KZGYgPC0gZGZba2VlcHNfZ2RwXQ0KbWVyZ2VfZGYgPC0gbWVyZ2UoZGYsIGRmXzMpICU+JSBtZXJnZShkZl8yKQ0KaGVhZChtZXJnZV9kZikNCmBgYA0KDQpgYGB7cn0NCiMgUmVtb3ZlIGFueSB1bm5lY2Vzc2FyeSBkYXRhDQpyZW1vdmUoZGYpDQpyZW1vdmUoZGZfMikNCnJlbW92ZShkZl8zKQ0KYGBgDQoNCmBgYHtyfQ0KZ2cgPC0gZ2dwbG90KG1lcmdlX2RmLCBhZXMoY29hbCwgZ2RwUGVyY2FwLCBjb2xvciA9IGNvbnRpbmVudCkpICsNCiAgZ2VvbV9wb2ludChhZXMoc2l6ZSA9IHBvcCwgZnJhbWUgPSB5ZWFyLCBpZHMgPSBjb3VudHJ5KSkgKw0KICBzY2FsZV94X2xvZzEwKCkgKyANCiAgc2NhbGVfeV9sb2cxMCgpICsNCiAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQ0KZ2dwbG90bHkoZ2cpDQpgYGANCg0KQWRkIGEgbmV3IGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqSW5zZXJ0IENodW5rKiBidXR0b24gb24gdGhlIHRvb2xiYXIgb3IgYnkgcHJlc3NpbmcgKkN0cmwrQWx0K0kqLg0KDQpXaGVuIHlvdSBzYXZlIHRoZSBub3RlYm9vaywgYW4gSFRNTCBmaWxlIGNvbnRhaW5pbmcgdGhlIGNvZGUgYW5kIG91dHB1dCB3aWxsIGJlIHNhdmVkIGFsb25nc2lkZSBpdCAoY2xpY2sgdGhlICpQcmV2aWV3KiBidXR0b24gb3IgcHJlc3MgKkN0cmwrU2hpZnQrSyogdG8gcHJldmlldyB0aGUgSFRNTCBmaWxlKS4NCg0KVGhlIHByZXZpZXcgc2hvd3MgeW91IGEgcmVuZGVyZWQgSFRNTCBjb3B5IG9mIHRoZSBjb250ZW50cyBvZiB0aGUgZWRpdG9yLiBDb25zZXF1ZW50bHksIHVubGlrZSAqS25pdCosICpQcmV2aWV3KiBkb2VzIG5vdCBydW4gYW55IFIgY29kZSBjaHVua3MuIEluc3RlYWQsIHRoZSBvdXRwdXQgb2YgdGhlIGNodW5rIHdoZW4gaXQgd2FzIGxhc3QgcnVuIGluIHRoZSBlZGl0b3IgaXMgZGlzcGxheWVkLg0K